package HousingService.task2.serialization.serializator;

import HousingService.task1.actor.Address;
import HousingService.task1.actor.Dispatcher;
import HousingService.task1.actor.Renter;
import HousingService.task1.actor.Worker;
import HousingService.task1.document.Request;
import HousingService.task1.document.WorkPlan;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

/**
 * Writes objects of 'Housing Service' subject area into .jsn files
 *
 * Default output files are set in inherited constructor by constants values
 *
 * Can change destination output file by calling setXXXXXXOut(File newOutFile)
 *
 * Created by IntelliJ IDEA.
 * User: Linderhof
 * Date: 30.11.2010
 * Time: 20:46:35
 */
public class JSNWriter extends AbstractWriter {
    private static final short spacesInIndent = 4;
    /**
     * Constants for setting default output files
     */
    //d:\epam-bravo-2010\timoshenko_housing\src\main\resources\jsn\
    protected final String DEFAULT_DIR_PATH =
            new String("d:\\epam-bravo-2010\\timoshenko_housing\\src\\main\\resources\\jsn\\");
    protected final String FORMAT =
            new String(".jsn");
    protected final String DEFAULT_RENTER_OUT_PATH =
            new String(DEFAULT_DIR_PATH + "renters" + FORMAT);
    protected final String DEFAULT_ADDRESS_OUT_PATH =
            new String(DEFAULT_DIR_PATH + "addresses" + FORMAT);
    protected final String DEFAULT_WORKER_OUT_PATH =
            new String(DEFAULT_DIR_PATH + "workers" + FORMAT);
    protected final String DEFAULT_DISPATCHER_OUT_PATH =
            new String(DEFAULT_DIR_PATH + "dispatchers" + FORMAT);
    protected final String DEFAULT_REQUEST_OUT_PATH =
            new String(DEFAULT_DIR_PATH + "requests" + FORMAT);
    protected final String DEFAULT_WORK_PLAN_OUT_PATH =
            new String(DEFAULT_DIR_PATH + "workPlan" + FORMAT);


    public JSNWriter() {
        setDefaultOutput();        
    }


    @Override
    protected void setDefaultOutput() {
        this.setRentersOut(new File(DEFAULT_RENTER_OUT_PATH));
        this.setAddressOut(new File(DEFAULT_ADDRESS_OUT_PATH));
        this.setWorkerOut(new File(DEFAULT_WORKER_OUT_PATH));
        this.setDispatcherOut(new File(DEFAULT_DISPATCHER_OUT_PATH));
        this.setRequestOut(new File(DEFAULT_REQUEST_OUT_PATH));
        this.setWorkPlanOut(new File(DEFAULT_WORK_PLAN_OUT_PATH));
    }

    private String placeIndent(short indentLevel) {
        StringBuffer spaces = new StringBuffer();
        short spacesCount = (short) (spacesInIndent * indentLevel);
        for(short i = 0; i < spacesCount; i++) {
            spaces.append(" ");
        }
        return spaces.toString();
    }

    private String writeField(String name, Object val, short level) {
        String opening = "\"";
        String nameEnd = "\":";
        String tab = "\t";
        String valEnd = "\",\n";

        StringBuilder field = new StringBuilder(placeIndent(level));
        field.append(opening);
        field.append(name);
        field.append(nameEnd);
        field.append(tab);
        field.append(opening);
        field.append(val);
        field.append(valEnd);

        return field.toString();
    }

    private String writeObjectOp(String name) {
        String op = "{\"";
        String end = "\":\t{\n";

        StringBuilder objectOp = new StringBuilder();
        objectOp.append(op);
        objectOp.append(name);
        objectOp.append(end);

        return objectOp.toString();
    }

    private String writeObjectEnd() {
        return "}}\n\n";
    }

    /*private StringBuilder writeMemberObject() {

    }*/


    /**
     * 
     * Hardcoded version
     * 
     * @param renter
     */
    public void write(Renter renter) {
        StringBuilder buffer = new StringBuilder();
        short indentLevel = 0;
        FileWriter out = null;

        try {
            //Every new Renter appends to existing file 
            out = new FileWriter(this.getRentersOut(), true);

            buffer.append(writeObjectOp("Renter"));

            ++indentLevel;
            buffer.append(writeField("renter_id", renter.get_id(), indentLevel));
            buffer.append(writeField("firstName", renter.get_firstName(), indentLevel) );
            buffer.append(writeField("lastName", renter.get_lastName(), indentLevel));

            //adding member class Address
            buffer.append(placeIndent(indentLevel));
            buffer.append("\"address\":\n");
            Address address = renter.get_address();
            ++indentLevel;
            buffer.append(placeIndent(indentLevel));
            buffer.append("\"Address\":\t{\n");
            ++indentLevel;
            buffer.append(writeField("address_id", address.get_address_id(), indentLevel));
            buffer.append(writeField("street", address.get_street(), indentLevel));
            buffer.append(writeField("house", address.get_houseNumber(), indentLevel));
            buffer.append(writeField("flat", address.get_flatNumber(), indentLevel) );

            buffer.append(writeObjectEnd());

            out.write(buffer.toString());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    //ignore                    
                }
            }
        }
    }

    public void write(Address address) {
        StringBuilder buffer = new StringBuilder();
        short indentLevel = 0;
        FileWriter out = null;

        try {
            out = new FileWriter(super.getAddressOut(), true);

            buffer.append(writeObjectOp("Address"));
            ++indentLevel;
            buffer.append(writeField("address_id", address.get_address_id(), indentLevel));
            buffer.append(writeField("street", address.get_street(), indentLevel));
            buffer.append(writeField("house", address.get_houseNumber(), indentLevel));
            buffer.append(writeField("flat", address.get_flatNumber(), indentLevel) );
            buffer.append(writeObjectEnd());

            out.write(buffer.toString());

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    //ignore
                }
            }
        }
    }

    public void write(Worker worker) {
        //To change body of implemented methods use File | Settings | File Templates.
    }

    public void write(Dispatcher dispatcher) {
        //To change body of implemented methods use File | Settings | File Templates.
    }

    public void write(Request request) {
        //To change body of implemented methods use File | Settings | File Templates.
    }

    public void write(WorkPlan workPlan) {
        //To change body of implemented methods use File | Settings | File Templates.
    }

    
}
